/** 
 * Project Name: farm-core 
 * File Name: XmlLoader.java 
 * Package Name: com.bugull.farm.core.frame.loader 
 * Date: 2017年3月20日上午10:44:30 
 * Copyright (c) 2017, hadlinks All Rights Reserved. 
 * 
 */
package com.bugull.farm.core.frame.loader;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.logging.log4j.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.bugull.farm.core.cache.ProtocolCache;
import com.bugull.farm.core.frame.filewatch.FileWatchService;
import com.bugull.farm.core.frame.structure.Param;

/** 
 * ClassName: XmlLoader 
 * Function: 加载XML协议命令模板的加载器，当对应的源文件（*.xml）被修改时，可实时重载.  
 * date: 2017年3月20日 上午10:44:30  
 * 
 * @author songwei (songw@hadlinks.com)
 * @version 
 * @since JDK 1.8 
 */
public class XmlLoader extends AbstractLoader{

	private final Logger logger  =  LogManager.getLogger(XmlLoader.class);
	
	@Override
	public void load(String path){
		try{
			File dir = new File(path);
			File[] fileList = dir.listFiles();
			//先加载公共的协议头
			for(File file : fileList){
				if(!file.isFile()){
					continue;
				}
				if(!file.getName().endsWith("xml")){
					continue;
				}
				if(file.isFile() && file.getName().contains("head")){//加载公共头格式定义的xml文件
					InputStream inputStream = new FileInputStream(file);  
					//使用saxReader读取xml文件
					SAXReader saxReader = new SAXReader();  
					Document document = saxReader.read(inputStream);  
					//解析xml中定义的node节点信息
					Element root = document.getRootElement();  
					//根节点，标示项目名称
					System.out.println("rootElement："+root.getName());
					//加载request模板，request节点，标识命令的类型
					Element head = root.element("head");
					@SuppressWarnings("unchecked")
					Iterator<Element> reqChildren = head.elements("attribute").iterator();
					List<Param> headList = new ArrayList<Param>();
					//具体的命令类型，如果是命令头，固定为head，其余为各个命令的命令字
					String cmd = head.attributeValue("type");
					int currentIndex = 0;
					while(reqChildren.hasNext()){
						Element child = reqChildren.next();
						Param param = new Param();
						if(child.attributeValue("isCmd") != null){
							param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
							param.setIndex(Integer.valueOf(child.attributeValue("index")));
						}else{
							param.setCmd(false);
						}
						param.setName(child.attributeValue("name"));
						ProtocolCache.getInstance().addIndex(child.attributeValue("name"), currentIndex);
						if(child.attributeValue("type").equals("fixed")){
							param.setLen(Integer.valueOf(child.attributeValue("len")));
							currentIndex += Integer.valueOf(child.attributeValue("len"));
						}
						param.setType(child.attributeValue("type"));
						if(child.attributeValue("type").equals("varying")){
							param.setDepend(child.attributeValue("depend"));
						}
						headList.add(param);
					}
					ProtocolCache.getInstance().addHead(cmd, headList);
				}else{//加载每个命令对应的xml文件
					InputStream inputStream = new FileInputStream(file);  
					//使用saxReader读取xml文件
					SAXReader saxReader = new SAXReader();  
					Document document = saxReader.read(inputStream);  
					//解析xml中定义的node节点信息
					Element root = document.getRootElement();  
					//加载request模板
					Element request = root.element("request");
					@SuppressWarnings("unchecked")
					Iterator<Element> reqChildren = request.elements("attribute").iterator();
					List<Param> reqList = new ArrayList<Param>();
					String cmd = request.attributeValue("type");
					while(reqChildren.hasNext()){
						Element child = reqChildren.next();
						Param param = new Param();
						if(child.attributeValue("isCmd") != null){
							param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
							param.setIndex(Integer.valueOf(child.attributeValue("index")));
						}else{
							param.setCmd(false);
						}
						param.setName(child.attributeValue("name"));
						if(child.attributeValue("type").equals("fixed")){
							param.setLen(Integer.valueOf(child.attributeValue("len")));
						}
						param.setType(child.attributeValue("type"));
						if(child.attributeValue("type").equals("varying")){
							param.setDepend(child.attributeValue("depend"));
						}
						reqList.add(param);
					}
					ProtocolCache.getInstance().addRequest(cmd, reqList);
					//加载response模板
					Element response = root.element("response");
					cmd = response.attributeValue("type");
					@SuppressWarnings("unchecked")
					Iterator<Element> resChildren = response.elements("attribute").iterator();
//					if(resChildren)
					List<Param> resList = new ArrayList<Param>();
					while(resChildren.hasNext()){
						Element child = resChildren.next();
						Param param = new Param();
						if(child.attributeValue("isCmd") != null){
							param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
							param.setIndex(Integer.valueOf(child.attributeValue("index")));
						}else{
							param.setCmd(false);
						}
						param.setName(child.attributeValue("name"));
						if(child.attributeValue("type").equals("fixed")){
							param.setLen(Integer.valueOf(child.attributeValue("len")));
						}
						param.setType(child.attributeValue("type"));
						if(child.attributeValue("type").equals("varying")){
							param.setDepend(child.attributeValue("depend"));
						}
						resList.add(param);
					}
					ProtocolCache.getInstance().addResponse(cmd, resList);
				}
			}
			//加载完成后，启动一个FileWatchService来对文件修改状态进行监控，如果监听到文件修改，则重新加载修改后的文件内容
			FileWatchService service = new FileWatchService();
			new Thread(() -> service.addWatcher(path, this)).start();
		}catch(Exception e){
			e.printStackTrace();
			logger.error(e);
		}
	}

	@Override
	public void reload(String path) {
		try{
			File file = new File(path);
			if(!file.isFile()){
				return;
			}
			if(!file.getName().endsWith("xml")){
				return;
			}
			if(file.isFile() && file.getName().contains("head")){//加载公共头格式定义的xml文件
				InputStream inputStream = new FileInputStream(file);  
				//使用saxReader读取xml文件
				SAXReader saxReader = new SAXReader();  
				Document document = saxReader.read(inputStream);  
				//解析xml中定义的node节点信息
				Element root = document.getRootElement();  
				//根节点，标示项目名称
				System.out.println("rootElement："+root.getName());
				//加载request模板，request节点，标识命令的类型
				Element head = root.element("head");
				@SuppressWarnings("unchecked")
				Iterator<Element> reqChildren = head.elements("attribute").iterator();
				List<Param> headList = new ArrayList<Param>();
				//具体的命令类型，如果是命令头，固定为head，其余为各个命令的命令字
				String cmd = head.attributeValue("type");
				while(reqChildren.hasNext()){
					Element child = reqChildren.next();
					Param param = new Param();
					if(child.attributeValue("isCmd") != null){
						param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
						param.setIndex(Integer.valueOf(child.attributeValue("index")));
					}else{
						param.setCmd(false);
					}
					param.setName(child.attributeValue("name"));
					if(child.attributeValue("type").equals("fixed")){
						param.setLen(Integer.valueOf(child.attributeValue("len")));
					}
					param.setType(child.attributeValue("type"));
					if(child.attributeValue("type").equals("varying")){
						param.setDepend(child.attributeValue("depend"));
					}
					headList.add(param);
				}
				ProtocolCache.getInstance().addHead(cmd, headList);
			}else{//加载每个命令对应的xml文件
				InputStream inputStream = new FileInputStream(file);  
				//使用saxReader读取xml文件
				SAXReader saxReader = new SAXReader();  
				Document document = saxReader.read(inputStream);  
				//解析xml中定义的node节点信息
				Element root = document.getRootElement();  
				//加载request模板
				Element request = root.element("request");
				@SuppressWarnings("unchecked")
				Iterator<Element> reqChildren = request.elements("attribute").iterator();
				List<Param> reqList = new ArrayList<Param>();
				String cmd = request.attributeValue("type");
				while(reqChildren.hasNext()){
					Element child = reqChildren.next();
					Param param = new Param();
					if(child.attributeValue("isCmd") != null){
						param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
						param.setIndex(Integer.valueOf(child.attributeValue("index")));
					}else{
						param.setCmd(false);
					}
					param.setName(child.attributeValue("name"));
					if(child.attributeValue("type").equals("fixed")){
						param.setLen(Integer.valueOf(child.attributeValue("len")));
					}
					param.setType(child.attributeValue("type"));
					if(child.attributeValue("type").equals("varying")){
						param.setDepend(child.attributeValue("depend"));
					}
					reqList.add(param);
				}
				ProtocolCache.getInstance().addRequest(cmd, reqList);
				//加载response模板
				Element response = root.element("response");
				@SuppressWarnings("unchecked")
				Iterator<Element> resChildren = response.elements("attribute").iterator();
				List<Param> resList = new ArrayList<Param>();
				while(resChildren.hasNext()){
					Element child = resChildren.next();
					Param param = new Param();
					if(child.attributeValue("isCmd") != null){
						param.setCmd(child.attributeValue("isCmd").equals("true")?true:false);
						param.setIndex(Integer.valueOf(child.attributeValue("index")));
					}else{
						param.setCmd(false);
					}
					param.setName(child.attributeValue("name"));
					if(child.attributeValue("type").equals("fixed")){
						param.setLen(Integer.valueOf(child.attributeValue("len")));
					}
					param.setType(child.attributeValue("type"));
					if(child.attributeValue("type").equals("varying")){
						param.setDepend(child.attributeValue("depend"));
					}
					resList.add(param);
				}
				ProtocolCache.getInstance().addResponse(cmd, resList);
			}
		}catch(Exception e){
			e.printStackTrace();
			logger.error(e);
		}
	}

}
